﻿namespace Nomo.CoreModule
{
    /// <summary>
    /// 实用流。
    /// </summary>
    public sealed unsafe class UtilityStream : System.IO.Stream
    {
        private byte[] _buffer;
        private int    _position;
        private int    _length;
        private int    _capacity;
        private bool   _isOpen;

        /// <summary>
        /// 初始化 <see cref="UtilityStream"/> 类的新实例。
        /// </summary>
        public UtilityStream() : this(0) { }

        /// <summary>
        /// 初始化具有指定内部缓冲区容量的 <see cref="UtilityStream"/> 类的新实例。
        /// </summary>
        /// <param name="capacity">内部缓冲区的初始大小。</param>
        /// <exception cref="System.ArgumentOutOfRangeException"><paramref name="capacity"/> 小于 0 .</exception>
        public UtilityStream(int capacity)
        {
            if (capacity < 0)
            {
                throw new System.ArgumentOutOfRangeException(nameof(capacity));
            }

            _buffer   = new byte[capacity];
            _position = 0;
            _length   = 0;
            _capacity = capacity;
            _isOpen   = true;
        }

        /// <inheritdoc />
        public override bool CanRead => _isOpen;

        /// <inheritdoc />
        public override bool CanSeek => _isOpen;

        /// <inheritdoc />
        public override bool CanWrite => _isOpen;

        /// <summary>
        /// 获取内部缓冲区的值。
        /// </summary>
        /// <exception cref="System.ObjectDisposedException">流已经关闭。</exception>
        public byte[] Buffer
        {
            get
            {
                if (!_isOpen)
                {
                    throw new System.ObjectDisposedException(default);
                }
                return _buffer;
            }
        }

        /// <summary>
        /// 获取内部缓冲区的只读引用（性能优于 <see cref="Buffer"/>）。
        /// </summary>
        /// <exception cref="System.ObjectDisposedException">流已经关闭。</exception>
        public ref readonly byte[] BufferReadonlyReference
        {
            get
            {
                if (!_isOpen)
                {
                    throw new System.ObjectDisposedException(default);
                }
                return ref _buffer;
            }
        }

        /// <inheritdoc />
        public override long Position
        {
            get
            {
                if (!_isOpen)
                {
                    throw new System.ObjectDisposedException(default);
                }
                return _position;
            }
            set
            {
                if (!_isOpen)
                {
                    throw new System.ObjectDisposedException(default);
                }
                var intValue = (int) value;
                if (intValue < 0)
                {
                    throw new System.ArgumentOutOfRangeException(nameof(value));
                }
                _position = intValue;
            }
        }

        /// <inheritdoc />
        public override long Length
        {
            get
            {
                if (!_isOpen)
                {
                    throw new System.ObjectDisposedException(default);
                }
                return _length;
            }
        }

        /// <summary>
        /// 获取或设置内部缓冲区的大小。
        /// </summary>
        /// <exception cref="System.ObjectDisposedException">流已经关闭。</exception>
        /// <exception cref="System.ArgumentOutOfRangeException">要设置的内部缓冲区的大小小于流的长度。此种情况下，请先调用 <see cref="SetLength"/> .</exception>
        public int Capacity
        {
            get
            {
                if (!_isOpen)
                {
                    throw new System.ObjectDisposedException(default);
                }
                return _capacity;
            }
            set
            {
                if (!_isOpen)
                {
                    throw new System.ObjectDisposedException(default);
                }
                if (value < _length)
                {
                    throw new System.ArgumentOutOfRangeException(nameof(value));
                }
                if (value == _capacity)
                {
                    return;
                }
                var buffer = new byte[value];
                if (_length != 0)
                {
                    System.Array.Copy(_buffer, 0, buffer, 0, _length);
                }
                _buffer   = buffer;
                _capacity = value;
            }
        }

        /// <inheritdoc />
        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                _buffer   = default;
                _position = default;
                _length   = default;
                _capacity = default;
                _isOpen   = default;
            }

            base.Dispose(disposing);
        }

        /// <summary>
        /// 重写 <see cref="System.IO.Stream.Flush"/> 方法以便不执行任何操作。
        /// </summary>
        public override void Flush() { }

        /// <inheritdoc />
        public override long Seek(long offset, System.IO.SeekOrigin origin)
        {
            if (!_isOpen)
            {
                throw new System.ObjectDisposedException(default);
            }
            switch (origin)
            {
                case System.IO.SeekOrigin.Begin:
                    if ((int) offset < 0)
                    {
                        throw new System.IO.IOException("试图将流中的当前位置设置在流的开始位置之前。");
                    }
                    _position = (int) offset;
                    break;
                case System.IO.SeekOrigin.Current:
                    if (_position + (int) offset < 0)
                    {
                        throw new System.IO.IOException("试图将流中的当前位置设置在流的开始位置之前。");
                    }
                    _position += (int) offset;
                    break;
                case System.IO.SeekOrigin.End:
                    if (_length + (int) offset < 0)
                    {
                        throw new System.IO.IOException("试图将流中的当前位置设置在流的开始位置之前。");
                    }
                    _position = _length + (int) offset;
                    break;
                default:
                    throw new System.ArgumentOutOfRangeException(nameof(origin), origin, null);
            }
            return _position;
        }

        /// <inheritdoc />
        public override void SetLength(long value)
        {
            if ((int) value < 0)
            {
                throw new System.ArgumentOutOfRangeException(nameof(value));
            }
            if (value == _length)
            {
                return;
            }
            _length = (int) value;
            if (value > _capacity)
            {
                if (_capacity == int.MaxValue)
                {
                    return;
                }
                long capacity = _capacity;
                if (capacity == 0)
                {
                    capacity = 1;
                }
                while (capacity < value)
                {
                    capacity <<= 1;
                }
                if (capacity > int.MaxValue)
                {
                    capacity = int.MaxValue;
                }
                var buffer = new byte[(int) capacity];
                System.Array.Copy(_buffer, 0, buffer, 0, _capacity);
                _buffer   = buffer;
                _capacity = (int) capacity;
            }
        }

        /// <summary>
        /// 将流的整个内容写入另一个流。
        /// </summary>
        /// <param name="stream">要写入此流的内容的流。</param>
        /// <exception cref="System.ArgumentNullException"><paramref name="stream"/> 为 <see langword="null"/> .</exception>
        /// <exception cref="System.ObjectDisposedException">流已经关闭。</exception>
        public void WriteTo(System.IO.Stream stream)
        {
            if (stream == null)
            {
                throw new System.ArgumentNullException(nameof(stream));
            }
            if (!_isOpen)
            {
                throw new System.ObjectDisposedException(default);
            }
            stream.Write(_buffer, 0, _length);
        }

        /// <summary>
        /// 将流的内容复制到新的字节数组，然后返回这个新的字节数组。
        /// </summary>
        /// <returns>与流的内容一致的新的字节数组。</returns>
        public byte[] ToArray()
        {
            var buffer = new byte[_length];
            System.Array.Copy(_buffer, 0, buffer, 0, _length);
            return buffer;
        }

        /// <inheritdoc />
        public override int Read(byte[] buffer, int offset, int count)
        {
            if (buffer == null)
            {
                throw new System.ArgumentNullException(nameof(buffer));
            }
            if (offset < 0)
            {
                throw new System.ArgumentOutOfRangeException(nameof(offset));
            }
            if (count < 0)
            {
                throw new System.ArgumentOutOfRangeException(nameof(count));
            }
            if (buffer.Length < offset + count)
            {
                throw new System.ArgumentException($"{nameof(offset)} 加 {nameof(count)} 的和超过了 {nameof(buffer)} 的长度。");
            }
            if (!_isOpen)
            {
                throw new System.ObjectDisposedException(default);
            }
            if (count == 0)
            {
                return 0;
            }
            count = System.Math.Min(count, _length - _position);
            if (count <= 0)
            {
                return 0;
            }
            System.Array.Copy(_buffer, _position, buffer, offset, count);
            _position += count;
            return count;
        }

        /// <summary>
        /// 从流中读取一个无符号字节，并将流内的位置向前提升 1 .
        /// </summary>
        /// <returns>读取到的无符号字节。</returns>
        /// <exception cref="System.ObjectDisposedException">流已经关闭。</exception>
        /// <exception cref="System.IO.IOException">从流内的当前位置开始到流的末尾的字节数不足，无法完成读取。</exception>
        public override int ReadByte()
        {
            if (!_isOpen)
            {
                throw new System.ObjectDisposedException(default);
            }
            if (_position > (long) _length - 1)
            {
                throw new System.IO.IOException("从流内的当前位置开始到流的末尾的字节数不足，无法完成读取。");
            }
            return Read1ByteInternal();
        }

        /// <summary>
        /// 从流中读取一个有符号字节，并将流内的位置向前提升 1 .
        /// </summary>
        /// <returns>读取到的有符号字节。</returns>
        /// <exception cref="System.ObjectDisposedException">流已经关闭。</exception>
        /// <exception cref="System.IO.IOException">从流内的当前位置开始到流的末尾的字节数不足，无法完成读取。</exception>
        public sbyte ReadSByte()
        {
            if (!_isOpen)
            {
                throw new System.ObjectDisposedException(default);
            }
            if (_position > (long) _length - 1)
            {
                throw new System.IO.IOException("从流内的当前位置开始到流的末尾的字节数不足，无法完成读取。");
            }
            return (sbyte) Read1ByteInternal();
        }

        /// <summary>
        /// 从流中读取一个布尔值，并将流内的位置向前提升 1 .
        /// </summary>
        /// <returns>读取到的布尔值。</returns>
        /// <exception cref="System.ObjectDisposedException">流已经关闭。</exception>
        /// <exception cref="System.IO.IOException">从流内的当前位置开始到流的末尾的字节数不足，无法完成读取。</exception>
        public bool ReadBool()
        {
            if (!_isOpen)
            {
                throw new System.ObjectDisposedException(default);
            }
            if (_position > (long) _length - 1)
            {
                throw new System.IO.IOException("从流内的当前位置开始到流的末尾的字节数不足，无法完成读取。");
            }
            return Read1ByteInternal() != default;
        }

        /// <summary>
        /// 从流中读取一个 Unicode 字符，并将流内的位置向前提升 2 .
        /// </summary>
        /// <returns>读取到的 Unicode 字符。</returns>
        /// <exception cref="System.ObjectDisposedException">流已经关闭。</exception>
        /// <exception cref="System.IO.IOException">从流内的当前位置开始到流的末尾的字节数不足，无法完成读取。</exception>
        public char ReadChar()
        {
            if (!_isOpen)
            {
                throw new System.ObjectDisposedException(default);
            }
            if (_position > (long) _length - 2)
            {
                throw new System.IO.IOException("从流内的当前位置开始到流的末尾的字节数不足，无法完成读取。");
            }
            return (char) Read2ByteInternal();
        }

        /// <summary>
        /// 从流中读取一个有符号 16 位整数，并将流内的位置向前提升 2 .
        /// </summary>
        /// <returns>读取到的有符号 16 位整数。</returns>
        /// <exception cref="System.ObjectDisposedException">流已经关闭。</exception>
        /// <exception cref="System.IO.IOException">从流内的当前位置开始到流的末尾的字节数不足，无法完成读取。</exception>
        public short ReadShort()
        {
            if (!_isOpen)
            {
                throw new System.ObjectDisposedException(default);
            }
            if (_position > (long) _length - 2)
            {
                throw new System.IO.IOException("从流内的当前位置开始到流的末尾的字节数不足，无法完成读取。");
            }
            return Read2ByteInternal();
        }

        /// <summary>
        /// 从流中读取一个无符号 16 位整数，并将流内的位置向前提升 2 .
        /// </summary>
        /// <returns>读取到的无符号 16 位整数。</returns>
        /// <exception cref="System.ObjectDisposedException">流已经关闭。</exception>
        /// <exception cref="System.IO.IOException">从流内的当前位置开始到流的末尾的字节数不足，无法完成读取。</exception>
        public ushort ReadUShort()
        {
            if (!_isOpen)
            {
                throw new System.ObjectDisposedException(default);
            }
            if (_position > (long) _length - 2)
            {
                throw new System.IO.IOException("从流内的当前位置开始到流的末尾的字节数不足，无法完成读取。");
            }
            return (ushort) Read2ByteInternal();
        }

        /// <summary>
        /// 从流中读取一个有符号 32 位整数，并将流内的位置向前提升 4 .
        /// </summary>
        /// <returns>读取到的有符号 32 位整数。</returns>
        /// <exception cref="System.ObjectDisposedException">流已经关闭。</exception>
        /// <exception cref="System.IO.IOException">从流内的当前位置开始到流的末尾的字节数不足，无法完成读取。</exception>
        public int ReadInt()
        {
            if (!_isOpen)
            {
                throw new System.ObjectDisposedException(default);
            }
            if (_position > (long) _length - 4)
            {
                throw new System.IO.IOException("从流内的当前位置开始到流的末尾的字节数不足，无法完成读取。");
            }
            return Read4ByteInternal();
        }

        /// <summary>
        /// 从流中读取一个无符号 32 位整数，并将流内的位置向前提升 4 .
        /// </summary>
        /// <returns>读取到的无符号 32 位整数。</returns>
        /// <exception cref="System.ObjectDisposedException">流已经关闭。</exception>
        /// <exception cref="System.IO.IOException">从流内的当前位置开始到流的末尾的字节数不足，无法完成读取。</exception>
        public uint ReadUInt()
        {
            if (!_isOpen)
            {
                throw new System.ObjectDisposedException(default);
            }
            if (_position > (long) _length - 4)
            {
                throw new System.IO.IOException("从流内的当前位置开始到流的末尾的字节数不足，无法完成读取。");
            }
            return (uint) Read4ByteInternal();
        }

        /// <summary>
        /// 从流中读取一个有符号 64 位整数，并将流内的位置向前提升 8 .
        /// </summary>
        /// <returns>读取到的有符号 64 位整数。</returns>
        /// <exception cref="System.ObjectDisposedException">流已经关闭。</exception>
        /// <exception cref="System.IO.IOException">从流内的当前位置开始到流的末尾的字节数不足，无法完成读取。</exception>
        public long ReadLong()
        {
            if (!_isOpen)
            {
                throw new System.ObjectDisposedException(default);
            }
            if (_position > (long) _length - 8)
            {
                throw new System.IO.IOException("从流内的当前位置开始到流的末尾的字节数不足，无法完成读取。");
            }
            return Read8ByteInternal();
        }

        /// <summary>
        /// 从流中读取一个无符号 64 位整数，并将流内的位置向前提升 8 .
        /// </summary>
        /// <returns>读取到的无符号 64 位整数。</returns>
        /// <exception cref="System.ObjectDisposedException">流已经关闭。</exception>
        /// <exception cref="System.IO.IOException">从流内的当前位置开始到流的末尾的字节数不足，无法完成读取。</exception>
        public ulong ReadULong()
        {
            if (!_isOpen)
            {
                throw new System.ObjectDisposedException(default);
            }
            if (_position > (long) _length - 8)
            {
                throw new System.IO.IOException("从流内的当前位置开始到流的末尾的字节数不足，无法完成读取。");
            }
            return (ulong) Read8ByteInternal();
        }

        /// <summary>
        /// 从流中读取一个单精度浮点数，并将流内的位置向前提升 8 .
        /// </summary>
        /// <returns>读取到的单精度浮点数。</returns>
        /// <exception cref="System.ObjectDisposedException">流已经关闭。</exception>
        /// <exception cref="System.IO.IOException">从流内的当前位置开始到流的末尾的字节数不足，无法完成读取。</exception>
        public float ReadFloat()
        {
            if (!_isOpen)
            {
                throw new System.ObjectDisposedException(default);
            }
            if (_position > (long) _length - 4)
            {
                throw new System.IO.IOException("从流内的当前位置开始到流的末尾的字节数不足，无法完成读取。");
            }
            var value = Read4ByteInternal();
            return *(float*) &value;
        }

        /// <summary>
        /// 从流中读取一个双精度浮点数，并将流内的位置向前提升 8 .
        /// </summary>
        /// <returns>读取到的双精度浮点数。</returns>
        /// <exception cref="System.ObjectDisposedException">流已经关闭。</exception>
        /// <exception cref="System.IO.IOException">从流内的当前位置开始到流的末尾的字节数不足，无法完成此操作。</exception>
        public double ReadDouble()
        {
            if (!_isOpen)
            {
                throw new System.ObjectDisposedException(default);
            }
            if (_position > (long) _length - 8)
            {
                throw new System.IO.IOException("从流内的当前位置开始到流的末尾的字节数不足，无法完成读取。");
            }
            var value = Read8ByteInternal();
            return *(double*) &value;
        }

        /// <summary>
        /// 从流中读取一个十进制数，并将流内的位置向前提升 16 .
        /// </summary>
        /// <returns>读取到的十进制数。</returns>
        /// <exception cref="System.ObjectDisposedException">流已经关闭。</exception>
        /// <exception cref="System.IO.IOException">从流内的当前位置开始到流的末尾的字节数不足，无法完成此操作。</exception>
        public decimal ReadDecimal()
        {
            if (!_isOpen)
            {
                throw new System.ObjectDisposedException(default);
            }
            if (_position > (long) _length - 16)
            {
                throw new System.IO.IOException("从流内的当前位置开始到流的末尾的字节数不足，无法完成读取。");
            }
            fixed (byte* ptr = &_buffer[_position])
            {
                var value = *(decimal*) ptr;
                _position += 16;
                return value;
            }
        }

        /// <inheritdoc />
        public override void Write(byte[] buffer, int offset, int count)
        {
            if (buffer == null)
            {
                throw new System.ArgumentNullException(nameof(buffer));
            }
            if (offset < 0)
            {
                throw new System.ArgumentOutOfRangeException(nameof(offset));
            }
            if (count < 0)
            {
                throw new System.ArgumentOutOfRangeException(nameof(count));
            }
            if (buffer.LongLength < (long) offset + count)
            {
                throw new System.ArgumentException($"{nameof(offset)} 加 {nameof(count)} 的和超过了 {nameof(buffer)} 的长度。");
            }
            if (!_isOpen)
            {
                throw new System.ObjectDisposedException(default);
            }
            if (count == 0)
            {
                return;
            }
            fixed (byte* ptr = &buffer[offset])
            {
                WriteInternal(ptr, count);
            }
        }

        /// <inheritdoc />
        public override void WriteByte(byte value)
        {
            Write(value);
        }

        /// <summary>
        /// 将一个无符号字节写入到流内的当前位置，并将流内的位置向前提升 1 .
        /// </summary>
        /// <param name="value">要写入的无符号字节。</param>
        /// <exception cref="System.ObjectDisposedException"></exception>
        public void Write(byte value)
        {
            if (!_isOpen)
            {
                throw new System.ObjectDisposedException(default);
            }
            WriteInternal(&value, 1);
        }

        /// <summary>
        /// 将一个有符号字节写入到流内的当前位置，并将流内的位置向前提升 1 .
        /// </summary>
        /// <param name="value">要写入的有符号字节。</param>
        /// <exception cref="System.ObjectDisposedException">流已经关闭。</exception>
        public void Write(sbyte value)
        {
            if (!_isOpen)
            {
                throw new System.ObjectDisposedException(default);
            }
            WriteInternal((byte*) &value, 1);
        }

        /// <summary>
        /// 将一个布尔值写入到流内的当前位置，并将流内的位置向前提升 1 .
        /// </summary>
        /// <param name="value">要写入的布尔值。</param>
        /// <exception cref="System.ObjectDisposedException">流已经关闭。</exception>
        public void Write(bool value)
        {
            if (!_isOpen)
            {
                throw new System.ObjectDisposedException(default);
            }
            WriteInternal((byte*) &value, 1);
        }

        /// <summary>
        /// 将一个 Unicode 字符写入到流内的当前位置，并将流内的位置向前提升 2 .
        /// </summary>
        /// <param name="value">要写入的 Unicode 字符。</param>
        /// <exception cref="System.ObjectDisposedException">流已经关闭。</exception>
        public void Write(char value)
        {
            if (!_isOpen)
            {
                throw new System.ObjectDisposedException(default);
            }
            WriteInternal((byte*) &value, 2);
        }

        /// <summary>
        /// 将一个有符号 16 位整数写入到流内的当前位置，并将流内的位置向前提升 2 .
        /// </summary>
        /// <param name="value">要写入的有符号 16 位整数。</param>
        /// <exception cref="System.ObjectDisposedException">流已经关闭。</exception>
        public void Write(short value)
        {
            if (!_isOpen)
            {
                throw new System.ObjectDisposedException(default);
            }
            WriteInternal((byte*) &value, 2);
        }

        /// <summary>
        /// 将一个无符号 16 位整数写入到流内的当前位置，并将流内的位置向前提升 2 .
        /// </summary>
        /// <param name="value">要写入的无符号 16 位整数。</param>
        /// <exception cref="System.ObjectDisposedException">流已经关闭。</exception>
        public void Write(ushort value)
        {
            if (!_isOpen)
            {
                throw new System.ObjectDisposedException(default);
            }
            WriteInternal((byte*) &value, 2);
        }

        /// <summary>
        /// 将一个有符号 32 位整数写入到流内的当前位置，并将流内的位置向前提升 4 .
        /// </summary>
        /// <param name="value">要写入的有符号 32 位整数。</param>
        /// <exception cref="System.ObjectDisposedException">流已经关闭。</exception>
        public void Write(int value)
        {
            if (!_isOpen)
            {
                throw new System.ObjectDisposedException(default);
            }
            WriteInternal((byte*) &value, 4);
        }

        /// <summary>
        /// 将一个无符号 32 位整数写入到流内的当前位置，并将流内的位置向前提升 4 .
        /// </summary>
        /// <param name="value">要写入的无符号 32 位整数。</param>
        /// <exception cref="System.ObjectDisposedException">流已经关闭。</exception>
        public void Write(uint value)
        {
            if (!_isOpen)
            {
                throw new System.ObjectDisposedException(default);
            }
            WriteInternal((byte*) &value, 4);
        }

        /// <summary>
        /// 将一个有符号 64 位整数写入到流内的当前位置，并将流内的位置向前提升 8 .
        /// </summary>
        /// <param name="value">要写入的有符号 64 位整数。</param>
        /// <exception cref="System.ObjectDisposedException">流已经关闭。</exception>
        public void Write(long value)
        {
            if (!_isOpen)
            {
                throw new System.ObjectDisposedException(default);
            }
            WriteInternal((byte*) &value, 8);
        }

        /// <summary>
        /// 将一个无符号 64 位整数写入到流内的当前位置，并将流内的位置向前提升 8 .
        /// </summary>
        /// <param name="value">要写入的无符号 64 位整数。</param>
        /// <exception cref="System.ObjectDisposedException">流已经关闭。</exception>
        public void Write(ulong value)
        {
            if (!_isOpen)
            {
                throw new System.ObjectDisposedException(default);
            }
            WriteInternal((byte*) &value, 8);
        }

        /// <summary>
        /// 将一个单精度浮点数写入到流内的当前位置，并将流内的位置向前提升 4 .
        /// </summary>
        /// <param name="value">要写入的单精度浮点数。</param>
        /// <exception cref="System.ObjectDisposedException">流已经关闭。</exception>
        public void Write(float value)
        {
            if (!_isOpen)
            {
                throw new System.ObjectDisposedException(default);
            }
            WriteInternal((byte*) &value, 4);
        }

        /// <summary>
        /// 将一个双精度浮点数写入到流内的当前位置，并将流内的位置向前提升 8 .
        /// </summary>
        /// <param name="value">要写入的双精度浮点数。</param>
        /// <exception cref="System.ObjectDisposedException">流已经关闭。</exception>
        public void Write(double value)
        {
            if (!_isOpen)
            {
                throw new System.ObjectDisposedException(default);
            }
            WriteInternal((byte*) &value, 8);
        }

        /// <summary>
        /// 将一个十进制数写入到流内的当前位置，并将流内的位置向前提升 16 .
        /// </summary>
        /// <param name="value">要写入的十进制数。</param>
        /// <exception cref="System.ObjectDisposedException">流已经关闭。</exception>
        public void Write(decimal value)
        {
            if (!_isOpen)
            {
                throw new System.ObjectDisposedException(default);
            }
            var ptr = (byte*) &value;
            WriteInternal(ptr,      4);
            WriteInternal(ptr + 4,  4);
            WriteInternal(ptr + 8,  4);
            WriteInternal(ptr + 12, 4);
        }

        #region 内部方法

        private void WriteInternal(byte* buffer, int count)
        {
            var length = (long) _position + count;
            if (length > _length)
            {
                long capacity = _capacity;
                if (length > capacity)
                {
                    if (capacity == int.MaxValue)
                    {
                        throw new System.IO.IOException("为了写入指定的内容，流需要扩充内部缓冲区，但内部缓冲区的长度已经达到上限，无法扩充。");
                    }
                    if (capacity == 0)
                    {
                        capacity = 1;
                    }
                    while (capacity < length)
                    {
                        capacity <<= 1;
                    }
                    if (capacity > int.MaxValue)
                    {
                        capacity = int.MaxValue;
                    }
                    var newBuffer = new byte[(int) capacity];
                    System.Array.Copy(_buffer, 0, newBuffer, 0, _capacity);
                    _buffer   = newBuffer;
                    _capacity = (int) capacity;
                }
                _length = (int) length;
            }
            while (count-- != 0)
            {
                _buffer[_position++] = *buffer++;
            }
        }

        private byte Read1ByteInternal()
        {
            return _buffer[_position++];
        }

        private short Read2ByteInternal()
        {
            fixed (byte* ptr = &_buffer[_position])
            {
                var value = *(short*) ptr;
                _position += 2;
                return value;
            }
        }

        private int Read4ByteInternal()
        {
            fixed (byte* ptr = &_buffer[_position])
            {
                var value = *(int*) ptr;
                _position += 4;
                return value;
            }
        }

        private long Read8ByteInternal()
        {
            fixed (byte* ptr = &_buffer[_position])
            {
                var value = *(long*) ptr;
                _position += 8;
                return value;
            }
        }

        #endregion
    }
}
